#include "xcom.h"
#include "function.h"
#include "device.h"
#include "serial.h"

static device_t _serial;

static uint8_t _check(uint8_t *buf,uint16_t len)
{
    uint8_t ret = 0;
    for(int i = 0; i < len;i++)
    {
        ret = ret + buf[i];
    }
    return ret;
}

static void _send_xcom(uint8_t sernum)
{
    uint8_t sndbuf[32] = {0};
    uint16_t sndlen = 0;
    sndbuf[sndlen++] = XCOM_ADDR;
    sndbuf[sndlen++] = XCOM_FRAME;
    sndbuf[sndlen++] = sernum;//ser nm
    sndbuf[sndlen++] = 0x00;
    uint8_t cs = fc_get_sum(sndbuf,sndlen);
    sndbuf[sndlen++] = ~(cs-1);

    _serial->write(0, sndbuf, sndlen, NULL);
}

uint32_t xcom_receive(XCOM_FILE* file, xcom_cb callback)
{
    uint8_t byte = 0;
    uint8_t first_flag = 0;

    uint32_t current_tick = 0;

    uint8_t state = 0;
    uint16_t revlen = 0;
    uint8_t revbuf[300] = {0};

    uint8_t sernum = 0;
    uint16_t needlen = 0;

    while(1)
    {
        // system_iwdg();
        if(_serial->readable() > 0)
        {
            current_tick = HAL_GetTick();

            _serial->read(0,&byte,1,NULL);
            if((state == 0)&&(byte == XCOM_ADDR))
                {state = 1;}
            else if(state == 1)
            {
                if(byte == XCOM_FRAME)
                    {state = 2;}
                else if(byte == XCOM_ADDR)
                    {state = 1;}
                else
                    {state = 0;}
            }
            else if(state == 2)
            {
                revlen = 0;
                revbuf[revlen++] = XCOM_ADDR;
                revbuf[revlen++] = XCOM_FRAME;
                revbuf[revlen++] = byte;
                state = 3;
            }
            else if(state == 3)
            {
                revbuf[revlen++] = byte;
                needlen = byte+5;
                state = 4;
            }
            else if(state == 4)
            {
                revbuf[revlen++] = byte;
                if(revlen >= needlen)
                {
                    state = 0;
                    if(_check(revbuf,revlen) == 0)
                    {
                        _send_xcom(revbuf[2]);
                        if(first_flag == 0)
                        {
                            first_flag = 1;
                            sernum = revbuf[2];
                        }
                        else
                        {
                            if(revbuf[2] == sernum)
                            {
                                continue;
                            }
                            sernum = revbuf[2];
                        }

                        uint8_t* pt_data = &revbuf[4];
                        uint16_t datalen = revbuf[3];

                        callback(file,pt_data,datalen);
                        file->seek = file->seek + datalen;
                    }
                }
            }
            else
            {
                state = 0;
                revlen = 0;
            }
        }
        else
        {
            if(current_tick > 0)
            {
                if(HAL_GetTick() - current_tick > 3000)
                {
                    file->length = file->seek;
                    break;
                }
            }
        }
    }

    return file->length;
}

void xcom_init(void *dev)
{
    _serial = dev;
    _serial->ioctl(CMD_REV_INIT, NULL);
}
